/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.tchepannou.limbe.engine;

import com.tchepannou.limbe.Interceptor;
import com.tchepannou.limbe.Service;
import com.tchepannou.limbe.Util;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import javax.servlet.ServletContext;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.File;
import java.io.IOException;

/**
 *
 * @author Herve Tchepannou
 */
public class EngineConfigurator
{
    //-- Public method
    public void configure (Engine engine, ServletContext sc)
        throws ConfigurationException
    {
        try
        {
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            DocumentBuilder db = dbf.newDocumentBuilder();
            
            String path = "/WEB-INF/limbe.xml";
            String xpath = sc.getRealPath (path);
            if (xpath == null)
            {
                throw new ConfigurationException(path + " not found");
            }
            
            Document doc = db.parse(new File(xpath));
            Element root = doc.getDocumentElement();
            NodeList children = root.getChildNodes();
            int count = children.getLength();
            for ( int i=0 ; i<count ; i++ )
            {
                Node node = children.item(i);
                if (node instanceof Element)
                {
                    Element elt = ( Element ) node;
                    handle (engine, elt);
                }
            }
        }
        catch (ParserConfigurationException e)
        {
            throw new ConfigurationException ( "Invalid configuration file", e);
        }
        catch (ClassNotFoundException e)
        {
            throw new ConfigurationException ( "Configuration error", e);
        }
        catch (InstantiationException e)
        {
            throw new ConfigurationException ( "Configuration error", e);
        }
        catch (IllegalAccessException e)
        {
            throw new ConfigurationException ( "Configuration error", e);
        }
        catch (SAXException e)
        {
            throw new ConfigurationException ( "Configuration error", e);
        }
        catch (IOException e)
        {
            throw new ConfigurationException ( "Configuration error", e);
        }
    }

    
    //-- Private
    @SuppressWarnings("unchecked")
    private void handle(Engine engine, Element elt)
        throws ClassNotFoundException,
               InstantiationException,
               IllegalAccessException
    {
        String name = elt.getTagName();
        String value = getTextValue(elt);
        if ( "login-url".equalsIgnoreCase (name) )
        {
            engine.setLoginURL (value);
        }
        else if ( "base-package".equalsIgnoreCase (name) )
        {
            engine.setBasePackage (value);
        }
        else if ("util-class".equalsIgnoreCase (name))
        {
            Class<? extends Util> clazz = (Class<? extends Util>)Class.forName (value);
            engine.setUtilClass (clazz);
        }
        else if ( "services".equalsIgnoreCase (name) )
        {
            configureServices (engine, elt);
        }
        else if ("action-interceptors".equalsIgnoreCase (name) )
        {
            configureActionInterceptors (engine, elt);
        }
        else if ("job-interceptors".equalsIgnoreCase (name) )
        {
            configureJobInterceptors (engine, elt);
        }
        else if ("mail-interceptors".equalsIgnoreCase (name) )
        {
            configureMailInterceptors (engine, elt);
        }
        else if ("message-interceptors".equalsIgnoreCase (name) )
        {
            configureMessageInterceptors (engine, elt);
        }
    }

    @SuppressWarnings({"unchecked", "rawtypes"})
    private void configureServices (Engine engine, Element root)
        throws ClassNotFoundException,
               InstantiationException,
               IllegalAccessException
    {
        NodeList children = root.getChildNodes();
        int count = children.getLength();
        for ( int i=0 ; i<count ; i++ )
        {
            Node node = children.item(i);
            if (node instanceof Element)
            {
                Element elt = ( Element ) node;
                String name = elt.getTagName();
                String value = getTextValue(elt);
                if ( "service".equalsIgnoreCase (name) )
                {
                    String type = elt.getAttribute("type");
                    Class typeClass = Class.forName (type);
                    Service service = ( Service ) Class.forName(value).newInstance ();
                    engine.registerService (typeClass, service);
                }
            }
        }
    }

    private void configureActionInterceptors (Engine engine, Element root)
        throws ClassNotFoundException,
               InstantiationException,
               IllegalAccessException
    {
        NodeList children = root.getChildNodes();
        int count = children.getLength();
        for ( int i=0 ; i<count ; i++ )
        {
            Node node = children.item(i);
            if (node instanceof Element)
            {
                Element elt = ( Element ) node;
                String name = elt.getTagName();
                String value = getTextValue(elt);
                if ( "interceptor".equalsIgnoreCase (name) )
                {
                    Interceptor interceptor = ( Interceptor ) Class.forName (value).newInstance ();
                    engine.registerActionInterceptor (interceptor);
                }
            }
        }
    }

    private void configureJobInterceptors (Engine engine, Element root)
        throws ClassNotFoundException,
               InstantiationException,
               IllegalAccessException
    {
        NodeList children = root.getChildNodes();
        int count = children.getLength();
        for ( int i=0 ; i<count ; i++ )
        {
            Node node = children.item(i);
            if (node instanceof Element)
            {
                Element elt = ( Element ) node;
                String name = elt.getTagName();
                String value = getTextValue(elt);
                if ( "interceptor".equalsIgnoreCase (name) )
                {
                    Interceptor interceptor = ( Interceptor ) Class.forName (value).newInstance ();
                    engine.registerJobInterceptor (interceptor);
                }
            }
        }
    }

    private void configureMailInterceptors (Engine engine, Element root)
        throws ClassNotFoundException,
               InstantiationException,
               IllegalAccessException
    {
        NodeList children = root.getChildNodes();
        int count = children.getLength();
        for ( int i=0 ; i<count ; i++ )
        {
            Node node = children.item(i);
            if (node instanceof Element)
            {
                Element elt = ( Element ) node;
                String name = elt.getTagName();
                String value = getTextValue(elt);
                if ( "interceptor".equalsIgnoreCase (name) )
                {
                    Interceptor interceptor = ( Interceptor ) Class.forName (value).newInstance ();
                    engine.registerMailInterceptor (interceptor);
                }
            }
        }
    }

    private void configureMessageInterceptors (Engine engine, Element root)
        throws ClassNotFoundException,
               InstantiationException,
               IllegalAccessException
    {
        NodeList children = root.getChildNodes();
        int count = children.getLength();
        for ( int i=0 ; i<count ; i++ )
        {
            Node node = children.item(i);
            if (node instanceof Element)
            {
                Element elt = ( Element ) node;
                String name = elt.getTagName();
                String value = getTextValue(elt);
                if ( "interceptor".equalsIgnoreCase (name) )
                {
                    Interceptor interceptor = ( Interceptor ) Class.forName (value).newInstance ();
                    engine.registerMessageInterceptor (interceptor);
                }
            }
        }
    }
    
    private String getTextValue(Element ele) 
    {
        Node node = ele.getFirstChild();
        String txt = node != null ? node.getNodeValue() : null;
        if (txt != null)
        {
            return txt.replaceAll("[\n\r]", "").trim();
        }
        return txt;
    }    
}
